﻿using Common.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Xmart.Action
{
    public abstract class AbstractAction : IAction
    {
        ILog log = LogManager.GetCurrentClassLogger();

        public ActionResult Execute(string name, params object[] args)
        {
            ActionResult ar = new ActionResult();
            log.DebugFormat("Execute:{0},Args{1}", name, args);
            try
            {
                var mi = FindMethod(name, typeof(object), args);

                log.DebugFormat("FindMethod:{0}", mi);

                ar = mi.Invoke(this, args) as ActionResult;
                ar.Success = true;
            }
            catch (Exception ex)
            {
                log.ErrorFormat("Error:{0}", ex, name);
                ar.Append("{0}:{1}", name, ex.Message);
                ar.State = -1;
                ar.Success = false;
            }

            return ar;
        }

        public ActionResult ExecuteQuery(string name, Type target, params object[] args)
        {
            ActionResult ar = new ActionResult();
            log.DebugFormat("Execute:{0},Args{1}", name, args);
            try
            {
                var mi = FindMethod(name, target, args);

                log.DebugFormat("FindMethod:{0}", mi);

                ar = mi.Invoke(this, args) as ActionResult;
                ar.Success = true;
            }
            catch (Exception ex)
            {
                log.ErrorFormat("Error:{0}", ex, name);
                ar.Append("{0}:{1}", name, ex.Message);
                ar.State = -1;
                ar.Success = false;
            }

            return ar;
        }

        private System.Reflection.MethodInfo FindMethod(string key, Type target, object[] args)
        {
            Type[] typeArgs = Type.EmptyTypes;

            if (args != null && args.Length > 0)
            {
                typeArgs = (from p in args where p != null select p.GetType()).ToArray();
            }

            var info = Spring.Util.ReflectionUtils.GetGenericMethod(this.GetType(), key, new Type[] { target }, typeArgs);
            if (info == null)
            {
                Type[] objArgs = (from ta in typeArgs select typeof(object)).ToArray();
                info = Spring.Util.ReflectionUtils.GetGenericMethod(this.GetType(), key, new Type[] { target }, objArgs);

                if (info == null)
                    info = Spring.Util.ReflectionUtils.GetMethod(GetType(), key, typeArgs);
            }
            return info;
        }

        protected virtual void ExecuteTransaction(System.Action action)
        {
            log.Debug("ExecuteTransaction");
            TransactionTemplate.Execute(delegate(Spring.Transaction.ITransactionStatus status)
            {
                action.Invoke();
                log.Debug("ExecuteTransaction Success");
                return null;
            });
        }

        public virtual Spring.Transaction.IPlatformTransactionManager TransactionManager
        {
            set { TransactionTemplate = new Spring.Transaction.Support.TransactionTemplate(value); }
        }

        protected virtual Spring.Transaction.Support.TransactionTemplate TransactionTemplate
        { get; set; }
    }
}
